# TODO: Add comment
# 
# Author: rogb
###############################################################################

setClass("DiscountFactor",
		contains=c("SituationDate","BasicDateData")
)

DiscountFactor <- function(SituationDate,Currency,Name,Date,Data){
	nCurrency <- length(Currency)
	if(missing(Name)){
		Name=character(nCurrency)
	}
	nName <- length(Name)
	if(nCurrency!=nName & (nName>0 &nCurrency>0)){
		stop("Name and Currency have different length")
	}
	nDate <- length(Date)
	Data <- as.matrix(Data)
	
	Dim <- dim(Data)
	nRowData <- Dim[1]
	nColData <- Dim[2]
	if((nRowData!=nDate) | (nColData!=nCurrency)){
		stop("Data, Name and Currency have different dimension")
	}
	if(SituationDate>min(Date)){
		stop("Date and Situation Date are incompatible")
	}
	new("DiscountFactor",SituationDate=SituationDate,Currency=Currency,Name=Name,Date=Date,Data=Data)
}
# x <- DiscountFactor(Sys.Date(),"CHF","BBB",Sys.Date()+(0:10)*1000,1*0.9999^((0:10)*1000))
setMethod("show","DiscountFactor",function(object){
			tmp <- object@Data
			rownames(tmp) <- as.character(object@Date)
			colnames(tmp) <- info(object)
			cat("Discount Factor as of ",as.character(object@SituationDate),"\n",sep="")
			print(tmp)
		})

# x <- DiscountFactor("CHF","BBB",Sys.Date()+0:1000,1*0.995^(0:1000))
# x <- DiscountFactor(Sys.Date(),c("CHF","EUR"),c("AAA","BBB"),Sys.Date()+0:1000,cbind(1*0.995^(0:1000),1*0.991^(0:1000)))
# plot(x)
setMethod("plot",signature=c("DiscountFactor"),function(x,y,...){
			n <- dim(x)[2]
			plotTitle <- paste("Discount Factor as of",as.character(x@SituationDate))
			plot(x@Date,x@Data[,1],main=plotTitle,typ="l",ylab="Discount Factor",xlab="Date",lwd=2,ylim=c(0,1),...)
			for(i in 1:n){
				lines(x@Date,x@Data[,i],col=i,lwd=2,...)
			}
			legend("topright",paste(x@Currency,x@Name),col=1:n,lwd=2,...)
		})

getDiscountFactor <- function(Date,InputDiscountFactor){
	# getDiscountFactor(Date,InputDiscountFactor)
	# InputDiscountFactor <- as.DiscountFactor(ZS)
	# Date <- Sys.Date()+20
	# Date <- Sys.Date()+400*3
	
	n <- dim(InputDiscountFactor)[2]
	nInputFactors <- dim(InputDiscountFactor)[1]
	# i <- 1
	if(InputDiscountFactor@Date[1]==InputDiscountFactor@SituationDate){
		x <- InputDiscountFactor@Date
	}else{
		x <- c(InputDiscountFactor@SituationDate,InputDiscountFactor@Date)
		nInputFactors <- nInputFactors + 1
	}
	xSituation <- InputDiscountFactor@SituationDate
	xout <- Date
	Data <- sapply(1:n,function(i,x,xout,InputDiscountFactor){
				# i <- 1
				if(InputDiscountFactor@Date[1]==InputDiscountFactor@SituationDate){
					y <- -log(InputDiscountFactor@Data[,i]) / yearFraction(xSituation,x)
				}
				else{
					y <- -log(c(1,InputDiscountFactor@Data[,i])) / yearFraction(xSituation,x)
				}
				y[1] <- y[2]
				yout1 <- exp(-approx(x,y,xout[xout<=x[nInputFactors]])$y * yearFraction(xSituation,xout[xout<=x[nInputFactors]]))
				r <- y[nInputFactors]
				yout2 <- exp(-r*yearFraction(xSituation,xout[xout>x[nInputFactors]]))
				yout <- c(yout1,yout2)
				yout
			},x,xout,InputDiscountFactor)
	if(length(Date)==1){
		Data <- t(Data)
	}
	DiscountFactor(InputDiscountFactor@SituationDate,InputDiscountFactor@Currency,InputDiscountFactor@Name,Date,Data)
}

setMethod("[",signature=c("DiscountFactor","Date","numeric"),function(x,i,j,drop){
			DF <- DiscountFactor(x@SituationDate,x@Currency[j],x@Name[j],x@Date,x@Data[,j])
			getDiscountFactor(i,DF)
		})

setMethod("[",signature=c("DiscountFactor","Date","missing"),function(x,i,j,drop){
			getDiscountFactor(i,x)
		})

setMethod("[",signature=c("DiscountFactor","Date","character"),function(x,i,j,drop){
			idx <- is.element(x@Currency,j)
			DF <- DiscountFactor(x@SituationDate,x@Currency[idx],x@Name[idx],x@Date,x@Data[,idx])
			getDiscountFactor(i,DF)
		})

# InputDiscountFactor <- DiscountFactor(Sys.Date(),"CHF","BBB",Sys.Date()+100,0.5)
# InputDiscountFactor <- DiscountFactor(Sys.Date(),c("CHF","EUR"),c("AAA","BBB"),Sys.Date()+(0:9)*500,cbind(1*0.9^(0:9),1*0.85^(0:9)))
# Date <- Sys.Date()+50:100
# y <- getDiscountFactor(Sys.Date()+10000,InputDiscountFactor)
# df1 <- DiscountFactor(Sys.Date(),"CHF","BBB",Sys.Date()+(0:9)*100,1*0.9^(0:9))
# df2 <- DiscountFactor(Sys.Date(),c("CHF","EUR"),c("AAA","BBB"),Sys.Date()+(0:9)*500,cbind(1*0.9^(0:9),1*0.85^(0:9)))
# df3 <-  DiscountFactor(Sys.Date(),"CHF","BBB",Sys.Date()+95,0.95)
# plot(merge(df1,df2,df3))
# ForwardSituationDate <- DateYMD(2022,4,18)
# ForwardSituationDate <- Sys.Date()+10
# forwardDiscountFactor(ForwardSituationDate,InputDiscountFactor)

forwardDiscountFactor <- function(ForwardSituationDate,InputDiscountFactor){
	if(length(ForwardSituationDate)>1){
		stop("ForwardSituationDate must have length 1")
	}
	ForwardDiscountFactor <- as.numeric(InputDiscountFactor[ForwardSituationDate,]@Data)
	if(dim(InputDiscountFactor)[1]==1 | all(ForwardSituationDate>=InputDiscountFactor@Date)){
		SpecialDate <- unique(ForwardSituationDate + c(0,as.numeric(InputDiscountFactor@Date - InputDiscountFactor@SituationDate)))
		SpecialDiscountFactor <- InputDiscountFactor[SpecialDate,]
		Data <- t(t(SpecialDiscountFactor@Data) / ForwardDiscountFactor)
		idx <- SpecialDiscountFactor@Date>ForwardSituationDate
		Date <- c(ForwardSituationDate,SpecialDiscountFactor@Date[idx])
		Data <- rbind(rep(1,dim(SpecialDiscountFactor)[2]),Data[idx,,drop=FALSE])
	}
	else{
		Data <- t(t(InputDiscountFactor@Data) / ForwardDiscountFactor)
		idx <- InputDiscountFactor@Date>ForwardSituationDate
		Date <- c(ForwardSituationDate,InputDiscountFactor@Date[idx])
		Data <- rbind(rep(1,dim(InputDiscountFactor)[2]),Data[idx,,drop=FALSE])
	}
	DiscountFactor(ForwardSituationDate,InputDiscountFactor@Currency,InputDiscountFactor@Name,Date,Data)
}




